package com.zohnblog.web.interceptor;

import com.zohnblog.model.domain.IPBanMode;
import com.zohnblog.service.IIPBanModeService;
import com.zohnblog.service.impl.WebStatisticServiceImpl;
import com.zohnblog.utils.Commons;
import org.springframework.security.core.userdetails.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.lang.Nullable;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/*
 * 自定义的Interceptor拦截器类，用于封装请求后的数据类到request域中，供html页面使用
 * 自定义MVC的Interceptor拦截器类有一下两点注意
 * 1.使用@Configuration注解声明
 * 2.自定义注册类将自定义的Interceptor拦截器类进行注册使用
 * */
@Configuration
public class IPInterceptor implements HandlerInterceptor {
    private static final Logger logger = LoggerFactory.getLogger(IPInterceptor.class);
    @Autowired
    private Commons commons;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private IIPBanModeService ipBanModeService;
    @Autowired
    WebStatisticServiceImpl webStatisticService;
    /**
     * 若开启了IP封禁模式,则拦截单位时间内操作次数超出最大操作次数的ip；
     * 拦截进行删除和修改操作的ip;
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String ipAddress = request.getRemoteAddr(); // ip地址

        // 判断是不是管理员账号
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (!"anonymousUser".equals(principal)) {
            User user = (User) principal;
            if ("admin".equals(user.getUsername())) {
                redisTemplate.delete(ipAddress);
                return true;
            }
        }
        IPBanMode ipBanMode = ipBanModeService.getOpenMode();
        // 若存在ipBanMode,则判断该ip是否操作频率过高
        if (ipBanMode != null) {
            Integer times = ipBanMode.getTimes(); // 当前ipBanMode的单位时间
            Integer maxRequests = ipBanMode.getMaxRequests(); // 当前模式单位时间内最大操作次数
            // 从redis中判断该ip是否第一次操作
            Object objIP = redisTemplate.opsForValue().get(ipAddress);
            if (objIP != null) {
                Integer requestTimes = (Integer) objIP;
                // 若超出最大操作次数,则封禁该ip
                if (requestTimes > maxRequests) {
                    logger.info("该ip:" + ipAddress + "操作频率过多,将禁止访问");
                    response.setHeader("Content-type", "text/html;charset=utf-8");
                    response.setCharacterEncoding("UTF-8");
                    response.getWriter().write("" + "<script>alert('你给封了,过" + times + "分钟再来吧');</script>");
                    return false;
                }
                logger.info("ip:" + ipAddress + "已连续请求" + requestTimes + "次");
                redisTemplate.opsForValue().set(ipAddress, requestTimes + 1, times, TimeUnit.MINUTES);
            } else {
                // 如果第一次访问则添加访问量统计
                webStatisticService.addRequests(new Date());
                logger.info("ip:" + ipAddress + "第一次访问");
                redisTemplate.opsForValue().set(ipAddress, 1, times, TimeUnit.MINUTES);
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           @Nullable ModelAndView modelAndView) throws Exception {
        // 用户将封装的Commons工具返回页面
        request.setAttribute("commons", commons);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                @Nullable Exception ex) throws Exception {
    }
}
